/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.pg.misra.GUI;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import pl.pg.misra.rules.XMLRule;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//pl.pg.misra.GUI//Config//EN",
autostore = false)
@TopComponent.Description(preferredID = "ConfigTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "commonpallete", openAtStartup = false)
@ActionID(category = "Window", id = "pl.pg.misra.GUI.ConfigTopComponent")
@ActionReference(path = "Menu/Window" /*
 * , position = 333
 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_ConfigAction",
preferredID = "ConfigTopComponent")
@Messages({
    "CTL_ConfigAction=Config",
    "CTL_ConfigTopComponent=Config Window",
    "HINT_ConfigTopComponent=This is a Config window"
})
public final class ConfigTopComponent extends TopComponent {
    private List<XMLRule> rules;
    private String clangPath;
    private XMLRule selectedRule;
    
    public ConfigTopComponent() {
        initComponents();
        setName(Bundle.CTL_ConfigTopComponent());
        setToolTipText(Bundle.HINT_ConfigTopComponent());
        setEnabledControls(false);
        
        clangPathText.setText(clangPath);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        buttonGroup1 = new javax.swing.ButtonGroup();
        buttonGroup2 = new javax.swing.ButtonGroup();
        jScrollPane2 = new javax.swing.JScrollPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        ruleList = new javax.swing.JList();
        jLabel1 = new javax.swing.JLabel();
        jScrollPane3 = new javax.swing.JScrollPane();
        nameTextArea = new javax.swing.JTextArea();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane4 = new javax.swing.JScrollPane();
        descriptionTextArea = new javax.swing.JTextArea();
        jLabel3 = new javax.swing.JLabel();
        requiredRadio = new javax.swing.JRadioButton();
        optionalRadio = new javax.swing.JRadioButton();
        jLabel4 = new javax.swing.JLabel();
        classNameField = new javax.swing.JTextField();
        cancelButton = new javax.swing.JButton();
        saveButton = new javax.swing.JButton();
        enabledCheckBox = new javax.swing.JCheckBox();
        applyButton = new javax.swing.JButton();
        jLabel5 = new javax.swing.JLabel();
        clangPathText = new javax.swing.JTextField();

        ruleList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        ruleList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        ruleList.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        ruleList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                ruleListValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(ruleList);

        jScrollPane2.setViewportView(jScrollPane1);

        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.jLabel1.text")); // NOI18N

        nameTextArea.setColumns(20);
        nameTextArea.setRows(5);
        nameTextArea.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                nameTextAreaKeyReleased(evt);
            }
        });
        jScrollPane3.setViewportView(nameTextArea);

        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.jLabel2.text")); // NOI18N

        descriptionTextArea.setColumns(20);
        descriptionTextArea.setRows(5);
        descriptionTextArea.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                descriptionTextAreaKeyReleased(evt);
            }
        });
        jScrollPane4.setViewportView(descriptionTextArea);

        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.jLabel3.text")); // NOI18N

        buttonGroup1.add(requiredRadio);
        org.openide.awt.Mnemonics.setLocalizedText(requiredRadio, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.requiredRadio.text")); // NOI18N
        requiredRadio.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                requiredRadioStateChanged(evt);
            }
        });

        buttonGroup1.add(optionalRadio);
        org.openide.awt.Mnemonics.setLocalizedText(optionalRadio, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.optionalRadio.text")); // NOI18N
        optionalRadio.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                optionalRadioStateChanged(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.jLabel4.text")); // NOI18N

        classNameField.setText(org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.classNameField.text")); // NOI18N
        classNameField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                classNameFieldKeyReleased(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.cancelButton.text")); // NOI18N
        cancelButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                cancelButtonMouseReleased(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(saveButton, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.saveButton.text")); // NOI18N
        saveButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                saveButtonMouseReleased(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(enabledCheckBox, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.enabledCheckBox.text")); // NOI18N
        enabledCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                enabledCheckBoxStateChanged(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(applyButton, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.applyButton.text")); // NOI18N
        applyButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                applyButtonMouseReleased(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.jLabel5.text")); // NOI18N

        clangPathText.setText(org.openide.util.NbBundle.getMessage(ConfigTopComponent.class, "ConfigTopComponent.clangPathText.text")); // NOI18N
        clangPathText.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                clangPathTextKeyReleased(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel2)
                                    .addComponent(jLabel4))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addComponent(jLabel1)
                                .addGap(30, 30, 30))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel5)
                                .addGap(24, 24, 24)))
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addComponent(clangPathText)
                                .addGap(18, 18, 18)
                                .addComponent(applyButton)
                                .addGap(18, 18, 18)
                                .addComponent(saveButton)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(cancelButton))
                            .addComponent(jScrollPane3)
                            .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 610, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(classNameField, javax.swing.GroupLayout.PREFERRED_SIZE, 294, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addComponent(jLabel3)
                                .addGap(18, 18, 18)
                                .addComponent(requiredRadio)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(optionalRadio))))
                    .addComponent(enabledCheckBox))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(enabledCheckBox)
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel1)
                                .addGap(0, 0, Short.MAX_VALUE))
                            .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel3)
                            .addComponent(requiredRadio)
                            .addComponent(optionalRadio)
                            .addComponent(classNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel4))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(cancelButton)
                                .addComponent(saveButton)
                                .addComponent(applyButton))
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel5)
                                .addComponent(clangPathText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                    .addComponent(jScrollPane2))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void ruleListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_ruleListValueChanged
        if (evt.getValueIsAdjusting() == false) {

            if (ruleList.getSelectedIndex() != -1) {
                selectedRule = rules.get(ruleList.getSelectedIndex());
                                
                descriptionTextArea.setText(selectedRule.getDescription());
                nameTextArea.setText(selectedRule.getName());
                classNameField.setText(selectedRule.getClassName());
                enabledCheckBox.setSelected(selectedRule.getEnabled());
                
                if (selectedRule.getType().equals("Required")){
                    requiredRadio.setSelected(true);
                }
                else{
                    optionalRadio.setSelected(true);
                }
                
                
                setEnabledControls(true);
            }
            else {
                selectedRule = null;
                
                setEnabledControls(false);
            }
        }
    }

    private void setEnabledControls(boolean value) {
        descriptionTextArea.setEnabled(value);
        nameTextArea.setEnabled(value);
        classNameField.setEnabled(value);
        enabledCheckBox.setEnabled(value);
        requiredRadio.setEnabled(value);
        optionalRadio.setEnabled(value);
    }//GEN-LAST:event_ruleListValueChanged

    private void cancelButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_cancelButtonMouseReleased
        this.close();
    }//GEN-LAST:event_cancelButtonMouseReleased

    private void saveButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_saveButtonMouseReleased
        try {
            saveChanges();
        } catch (ParserConfigurationException | FileNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformerConfigurationException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformerException ex) {
            Exceptions.printStackTrace(ex);
        }
        
        this.close();
    }//GEN-LAST:event_saveButtonMouseReleased

    private void applyButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_applyButtonMouseReleased
        try {
            saveChanges();
        } catch (ParserConfigurationException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformerConfigurationException ex) {
            Exceptions.printStackTrace(ex);
        } catch (TransformerException ex) {
            Exceptions.printStackTrace(ex);
        } catch (FileNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }

    }//GEN-LAST:event_applyButtonMouseReleased

    private void enabledCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_enabledCheckBoxStateChanged
        if (selectedRule != null){
            selectedRule.setEnabled(enabledCheckBox.isSelected());
        }
    }//GEN-LAST:event_enabledCheckBoxStateChanged

    private void nameTextAreaKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_nameTextAreaKeyReleased
        if (selectedRule != null){
            selectedRule.setName(nameTextArea.getText());
        }
    }//GEN-LAST:event_nameTextAreaKeyReleased

    private void classNameFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_classNameFieldKeyReleased
        if (selectedRule != null){
            selectedRule.setClassName(classNameField.getText());
        }
    }//GEN-LAST:event_classNameFieldKeyReleased

    private void requiredRadioStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_requiredRadioStateChanged
        if (selectedRule != null){
            if (requiredRadio.isSelected()){
                selectedRule.setType("Required");
            }
        }
    }//GEN-LAST:event_requiredRadioStateChanged

    private void optionalRadioStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_optionalRadioStateChanged
        if (selectedRule != null){
            if (optionalRadio.isSelected()){
                selectedRule.setType("Advisory");
            }
        }
    }//GEN-LAST:event_optionalRadioStateChanged

    private void descriptionTextAreaKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_descriptionTextAreaKeyReleased
        if (selectedRule != null){
            selectedRule.setDescription(descriptionTextArea.getText());
        }
    }//GEN-LAST:event_descriptionTextAreaKeyReleased

    private void clangPathTextKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_clangPathTextKeyReleased
        clangPath = clangPathText.getText();
    }//GEN-LAST:event_clangPathTextKeyReleased

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton applyButton;
    private javax.swing.ButtonGroup buttonGroup1;
    private javax.swing.ButtonGroup buttonGroup2;
    private javax.swing.JButton cancelButton;
    private javax.swing.JTextField clangPathText;
    private javax.swing.JTextField classNameField;
    private javax.swing.JTextArea descriptionTextArea;
    private javax.swing.JCheckBox enabledCheckBox;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTextArea nameTextArea;
    private javax.swing.JRadioButton optionalRadio;
    private javax.swing.JRadioButton requiredRadio;
    private javax.swing.JList ruleList;
    private javax.swing.JButton saveButton;
    // End of variables declaration//GEN-END:variables
    @Override
    public void componentOpened() {
        // TODO add custom code on component opening
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }
    
    public void loadRules(List<XMLRule> rules, String path){
        String[] listItems = new String[rules.size()];
        int counter = 0;
        
        clangPath = path;
        
        this.rules = rules;
        
        for (XMLRule rule :  this.rules){
            listItems[counter] = "Rule " + rule.getNumber();
            
            counter++;
        }
        
        ruleList.setListData(listItems);
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    private void saveChanges() throws ParserConfigurationException, TransformerConfigurationException, TransformerException, FileNotFoundException {
        File configFile = new File("config.xml");
        Document doc = buildDOMTree();

        TransformerFactory transfac = TransformerFactory.newInstance();
        Transformer trans = transfac.newTransformer();
        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        trans.setOutputProperty(OutputKeys.INDENT, "yes");

        StreamResult result = new StreamResult(new FileOutputStream(configFile));
        DOMSource source = new DOMSource(doc);
        trans.transform(source, result);
    }
    
    private Document buildDOMTree() throws DOMException, ParserConfigurationException {
        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
        Document doc = docBuilder.newDocument();
        
        Element root = doc.createElement("config");
        Element path = doc.createElement("clangPath");
        Element rulesElement = doc.createElement("rules");
        
        path.setTextContent(clangPath);
        
        doc.appendChild(root);
        root.appendChild(path);
        root.appendChild(rulesElement);
        
        
        for (XMLRule rule : rules){
            Element ruleElement = doc.createElement("rule");
            
            ruleElement.setAttribute("id", String.valueOf(rule.getId()));
            
            Element numberElement = doc.createElement("number");
            numberElement.setTextContent(rule.getNumber());
            
            Element nameElement = doc.createElement("name");
            nameElement.setTextContent(rule.getName());
            
            Element descElement = doc.createElement("description");
            descElement.setTextContent(rule.getDescription());
            
            Element typeElement = doc.createElement("type");
            typeElement.setTextContent(rule.getType());
            
            Element classElement = doc.createElement("className");
            classElement.setTextContent(rule.getClassName());
            
            Element enabledElement = doc.createElement("enabled");
            enabledElement.setTextContent(String.valueOf(rule.getEnabled()));
            
            ruleElement.appendChild(numberElement);
            ruleElement.appendChild(nameElement);
            ruleElement.appendChild(descElement);
            ruleElement.appendChild(typeElement);
            ruleElement.appendChild(classElement);
            ruleElement.appendChild(enabledElement);
            
            rulesElement.appendChild(ruleElement);
        }
        
        return doc;
    }
}
